﻿namespace Centido.Core.Test
{
    using System;
    using System.Data.Common;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// Testing string columns
    /// </summary>
    [TestClass]
    public class StringColumnTest : ColumnBaseTest<string>
    {
        /// <summary>
        /// Column
        /// </summary>
        private StringColumn Column
        {
            get { return GenericColumn as StringColumn; }
        }

        /// <summary>
        /// Get column type
        /// </summary>
        /// <returns></returns>
        protected override ColumnType GetColumnType()
        {
            return ColumnType.String;
        }

        /// <summary>
        /// Get large value
        /// </summary>
        /// <returns></returns>
        protected override string GetLargeValue()
        {
            return "Название на русском";
        }

        /// <summary>
        /// Get small data
        /// </summary>
        /// <returns></returns>
        protected override string GetSmallValue()
        {
            return "Другое название на русском";
        }

        /// <summary>
        /// Convert db value
        /// </summary>
        /// <param name="dbValue">Db value</param>
        /// <returns></returns>
        protected override string ConvertDbValue(object dbValue)
        {
            return DbValue.GetString(dbValue);
        }

        /// <summary>
        /// Setting default value with max length
        /// </summary>
        [TestMethod]
        public void SettingDefaultValueWithMaxLength()
        {
            var defaultValue = StringProperty.Value('Я', 2000);

            Column.DefaultValue = defaultValue;

            Assert.AreEqual(Column.DefaultValue, defaultValue);

            var id = Table.InsertRow();

            Assert.AreEqual(Column.Read(id).GetString(), StringProperty.Value('Я', 2000));
        }


        /// <summary>
        /// Reading and writing max length
        /// </summary>
        [TestMethod]
        public void ReadingAndWritingMaxLength()
        {
            //Initially max length must be null
            Assert.IsNull(Column.MaxLength);

            //Writing 1 to max length
            Column.MaxLength = 1;
            Column.MaxLength = 1;

            Assert.AreEqual(Column.MaxLength, 1);

            Column.Refresh();

            Assert.AreEqual(Column.MaxLength, 1);

            //Writing null to max length
            Column.MaxLength = null;
            Column.MaxLength = null;

            Assert.IsNull(Column.MaxLength);
        }

        /// <summary>
        /// Setting max length for deleted column
        /// </summary>
        [TestMethod]
        public void SettingMaxLengthForDeletedColumn()
        {
            GenericColumn.Delete();

            try
            {
                Column.MaxLength = 125;
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.ColumnWasNotFound);
                return;
            }

            Assert.Fail();
        }


        /// <summary>
        ///   Decreasing the MaxLength property for an indexed column (bug fix).
        /// </summary>
        [TestMethod]
        public void DecreasingMaxLengthForIndexedColumn()
        {
            Column.MaxLength = 20;

            var index = Table.AddIndex(GenericColumn);

            Column.MaxLength = 10;

            Assert.AreEqual(Column.MaxLength, 10);
            Assert.IsTrue(index.Exists());
        }


        /// <summary>
        /// Passing zero to max length
        /// </summary>
        [TestMethod]
        public void PassingZeroToMaxLength()
        {
            try
            {
                Column.MaxLength = 0;
            }
            catch (DbException)
            {
                Assert.IsNull(Column.MaxLength);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Passing negative value to max length
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void PassingNegativeValueToMaxLength()
        {
            Column.MaxLength = -1;
        }

        /// <summary>
        /// Inserting value shorter than max length
        /// </summary>
        [TestMethod]
        public void InsertingValueEqualToMaxLength()
        {
            //Setting new max length
            Column.MaxLength = StringProperty.ExtendedStringColumnLength;

            //New value
            var newValue = StringProperty.ExtendedValue('A');

            //Inserting new value
            var rowId = Table.InsertRow(GenericColumn.Value(newValue));

            Assert.AreEqual(Table.RowCount, 1);

            //Reading inserted value
            var inserted = GenericColumn.EmptyValue();

            Table.ReadRow(rowId, inserted);

            Assert.AreEqual(inserted.GetString(), newValue);
        }

        /// <summary>
        /// Inserting value greater than max length
        /// </summary>
        [TestMethod]
        public void InsertingValueLongerThanMaxLength()
        {
            //Setting max length to 1
            Column.MaxLength = 1;

            try
            {
                //Inserting too long value
                Table.InsertRow(GenericColumn.Value("AA"));
            }
            catch (DbException)
            {
                Assert.AreEqual(Table.RowCount, 0);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Setting max length after a value was inserted
        /// </summary>
        [TestMethod]
        public void SettingMaxLengthAfterValueWasInserted()
        {
            //Inserting a value
            Table.InsertRow(GenericColumn.Value("a"));

            Assert.AreEqual(Table.RowCount, 1);

            //Setting max length
            Column.MaxLength = 1;

            Assert.AreEqual(Column.MaxLength, 1);
        }

        /// <summary>
        /// Setting MaxLength after long value was inserted
        /// </summary>
        [TestMethod]
        public void SettingMaxLengthAfterLongValueWasInserted()
        {
            //Long value
            var longValue = StringProperty.ExtendedValue('A');

            //Inserting long value
            Table.InsertRow(GenericColumn.Value(longValue));

            Assert.AreEqual(Table.RowCount, 1);

            try
            {
                //Setting max length
                Column.MaxLength = 1;
            }
            catch (DbException)
            {
                Assert.IsNull(Column.MaxLength);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Setting too long default when max length is set
        /// </summary>
        [TestMethod]
        public void SettingTooLongDefaultValueWhenMaxLengthIsSet()
        {
            //Setting max length
            Column.MaxLength = 1;

            try
            {
                //Setting too long default value
                Column.DefaultValue = "Too long default value";

                //Inserting new row
                Table.InsertRow();
            }
            catch (DbException)
            {
                Assert.AreEqual(Table.RowCount, 0);
                return;
            }

            Assert.Fail();
        }


        /// <summary>
        ///   Changing the string column nullability after setting the maximum length (bug fix).
        /// </summary>
        [TestMethod]
        public void ChangingIsNotNullAfterMaxLength()
        {
            Column.MaxLength = 80;

            Assert.AreEqual(Column.MaxLength, 80);

            Column.IsNotNull = true;

            Assert.IsTrue(Column.IsNotNull);

            try
            {
                // Checking that the max length is indeed 80
                Table.InsertRow(Column.Value(StringProperty.Value('a', 81)));
            }
            catch (DbException)
            {
                Assert.AreEqual(Table.RowCount, 0);
                return;
            }

            Assert.Fail();
        }
    }
}